package com.pilipala.utils;

import com.aliyun.oss.*;
import com.aliyun.oss.common.comm.io.BoundedInputStream;
import com.aliyun.oss.model.*;
import com.pilipala.constant.MessageConstant;
import com.pilipala.exception.AliOSSException;
import com.pilipala.exception.UploadException;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.util.ArrayList;
import java.util.List;

@Data
@AllArgsConstructor
@Slf4j
public class AliOssUtil {

    private String endpoint;
    private String accessKeyId;
    private String accessKeySecret;
    private String bucketName;

    /**
     * 上传文件
     *
     * @param bytes      数据源
     * @param objectName 文件名称
     * @return 路径
     */
    public String upload(byte[] bytes, String objectName) {
//      上传文件的客户端
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        try {
            ossClient.putObject(bucketName, objectName, new ByteArrayInputStream(bytes));
        } catch (OSSException exception) {
//            错误日志
            log.error("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            log.error("Error OSSException Message:{}", exception.getErrorMessage());
            log.error("Error Code:{}", exception.getErrorCode());
            log.error("Request ID:{}", exception.getRequestId());
            log.error("Host ID:{}", exception.getHostId());
        } catch (ClientException exception) {
            log.error("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            log.error("Error ClientException Messages:{}", exception.getMessage());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
        //文件访问路径规则 https://BucketName.Endpoint/ObjectName
        StringBuilder builder = new StringBuilder("https://");
        builder.append(bucketName)
                .append(".")
                .append(endpoint)
                .append("/")
                .append(objectName);
        log.info("文件上传到:{}", builder.toString());
        return builder.toString();
    }

    public String uploadLargeFile(String objectName, MultipartFile file) {
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

        try (InputStream inputStream = file.getInputStream()) {
            // 1. 初始化分片任务
            InitiateMultipartUploadRequest initRequest = new InitiateMultipartUploadRequest(bucketName, objectName);
            InitiateMultipartUploadResult initResult = ossClient.initiateMultipartUpload(initRequest);
            String uploadId = initResult.getUploadId();

            // 2. 计算分片参数
            long fileSize = file.getSize();
            long partSize = 5 * 1024 * 1024; // 5MB
            int partCount = (int) ((fileSize + partSize - 1) / partSize);

            log.info("一共有{}分片",partCount);
            List<PartETag> partETags = new ArrayList<>();
            for (int i = 1; i <= partCount; i++) {
                long startPos = (i - 1) * partSize;
                long currentPartSize = (i == partCount) ? (fileSize - startPos) : partSize;

                byte[] buffer = new byte[(int) currentPartSize];
                int bytesRead = inputStream.read(buffer);

                log.info("现在是分片{}号  分片大小为:{}",i,currentPartSize);
                if (bytesRead == -1) break;

                InputStream partStream = new ByteArrayInputStream(buffer, 0, bytesRead);

                UploadPartRequest uploadPartRequest = new UploadPartRequest();
                uploadPartRequest.setBucketName(bucketName);
                uploadPartRequest.setKey(objectName);
                uploadPartRequest.setUploadId(uploadId);
                uploadPartRequest.setInputStream(partStream);
                uploadPartRequest.setPartSize(currentPartSize);
                uploadPartRequest.setPartNumber(i);

                UploadPartResult uploadResult = ossClient.uploadPart(uploadPartRequest);
                partETags.add(uploadResult.getPartETag());
            }
            log.info("合并分片");
            // 3. 合并分片
            CompleteMultipartUploadRequest completeRequest = new CompleteMultipartUploadRequest(
                    bucketName, objectName, uploadId, partETags
            );
            CompleteMultipartUploadResult completeResult = ossClient.completeMultipartUpload(completeRequest);
            log.info("合并完成,返回结果是:{}",completeResult.getLocation());
            return completeResult.getLocation();
        } catch (IOException e) {
            throw new UploadException(MessageConstant.UPLOAD_FAIL);
        } finally {
            ossClient.shutdown();
        }
    }

    public String get(String objectName){
//        构造客户端和获取请求
        OSS ossClient = new OSSClientBuilder().build(endpoint,accessKeyId,accessKeySecret);
        GetObjectRequest getObjectRequest = new GetObjectRequest(bucketName,objectName);
        log.info("获取的要素名称:{},获取请求:{}",objectName,getObjectRequest);
//        获取到对应数据
        OSSObject object = ossClient.getObject(getObjectRequest);
        InputStream inputStream = object.getObjectContent();

        BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
        StringBuilder strB = new StringBuilder();

        String line;

        try{
            while ((line = reader.readLine()) != null) {
                strB.append(line);
            }
//            关闭资源   这里图方便就直接在抛异常这里关闭了
            reader.close();
            inputStream.close();
        }catch (IOException exception){
            throw new AliOSSException(MessageConstant.GET_OBJECT_ERROR);
        }
        return strB.toString();
    }
}



